package com.melodyframe.common.tools.convert;

import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

public class ConvertUtil {

	public static ConvertUtil			util	= new ConvertUtil();

	private Map<String, Converter<?>>	converterDeclareMap;
	private Map<String, Converter<?>>	converterMap;

	private ConvertUtil() {
		this.converterDeclareMap = new LinkedHashMap<String, Converter<?>>();
		this.converterMap = new HashMap<String, Converter<?>>();
		this.init();
	}

	private void init() {
		InputStream propertyInStream = this.getClass().getResourceAsStream(
				"/melody/tools/converter.properties");
		InputStream userPropertyInStrean = this.getClass().getResourceAsStream(
				"/melody-converter.properties");
		Properties properties = new Properties();
		try {
			properties.load(propertyInStream);
			if (null != userPropertyInStrean) {
				properties.load(userPropertyInStrean);
			}
		} catch (Exception e) {
		}
		for (String key : properties.stringPropertyNames()) {
			this.addConvertor(key, properties.getProperty(key));
		}
	}

	private void addConvertor(String classType, String converterClass) {
		Converter<?> converter = null;
		if (this.converterMap.containsKey(converterClass)) {
			converter = this.converterMap.get(converterClass);
		} else {
			try {
				converter = (Converter<?>) Class.forName(converterClass)
						.newInstance();
				this.converterMap.put(converterClass, converter);
			} catch (Exception e) {
			}
		}
		if (null != converter) {
			this.converterDeclareMap.put(classType, converter);
		}
	}

	@SuppressWarnings("unchecked")
	private <T> Converter<T> getConverter(Class<?> classType) {

		Converter<T> propertyConvertor = (Converter<T>) this.converterDeclareMap
				.get(classType.getName());
		if (null != propertyConvertor) {
			return propertyConvertor;
		} else {
			return null;
		}

	}

	private static ConvertUtil getUtil() {
		return util;
	}

	/**
	 * Check the support of given class
	 * 
	 * @param classType
	 *            The
	 * @return Ture if supported, else false
	 */
	public static boolean support(Class<?> classType) {
		return getUtil().converterDeclareMap.containsKey(classType.getName());
	}

	/**
	 * Convert the object to given type with the given format
	 * 
	 * @param object
	 *            Source object
	 * @param classType
	 *            The type of target
	 * @param format
	 * @return The object of target
	 */
	public static <T> T convert(Object object, Class<T> classType, String format) {
		Converter<T> converter = getUtil().getConverter(classType);
		return converter.convert(object, classType, format);
	}

	/**
	 * Convert the object to given type
	 * 
	 * @param object
	 *            Source object
	 * @param classType
	 *            The type of target
	 * @return The object of target
	 */
	public static <T> T convert(Object object, Class<T> classType) {
		Converter<T> converter = getUtil().getConverter(classType);
		return converter.convert(object, classType, null);
	}
}
